﻿using MengCC.Common.Net;
using MengCC.Common.Serialize;
using MengCC.Plugin.SVN.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace MengCC.Plugin.SVN
{
    public class SVNDownloader
    {
        private readonly string uid;
        private readonly string pwd;
        private string url;
        private string origin;
        private string rootPath;

        private string httpContent;

        private List<Task> tasks;


        public SVNDownloader(string uid, string pwd, string url)
        {
            tasks = new List<Task>();
            this.uid = uid;
            this.pwd = pwd;
            this.url = url;
            var urlinfo = url.Split("/svn/", StringSplitOptions.None);
            origin = urlinfo[0];
            rootPath = urlinfo[1];

            httpContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?><propfind xmlns=\"DAV:\" xmlns:S=\"http://subversion.tigris.org/xmlns/svn/\"><prop><resourcetype xmlns=\"DAV:\" /><getcontentlength xmlns=\"DAV:\" /><version-name xmlns=\"DAV:\" /><creator-displayname xmlns=\"DAV:\" /><creationdate xmlns=\"DAV:\" /><checked-in xmlns=\"DAV:\" /><S:mime-type /></prop></propfind>";
        }


        private HttpWebRequest GetHttpRequest(string url)
        {
            var authInfo = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{uid}:{pwd}"));

            var handler = new HttpClientHandler()
            {
                AllowAutoRedirect = false,

            };

            var request =HttpHelper.GetHttpWebRequest(url);

            request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
            request.Headers.Add("Depth", $"1");
            request.Headers.Add("Authorization", $"Basic {authInfo}");
            request.Headers.Add("Origin", origin);
            request.Headers.Add("Referer", $"{origin}/!/");
            return request;
        }

        private async Task<multistatus> Request(string url)
        {
            var request = GetHttpRequest(url);
            request.Method = "PROPFIND";
            var stream =request.GetRequestStream();
            stream.Write(Encoding.UTF8.GetBytes(httpContent));

            var response =request.GetResponse();
            string rsp = HttpHelper.GetString(response);
            //rsp = new Regex(":|-").Replace(rsp, "_");
            //rsp = rsp.Replace("utf_8", "utf-8");
            try
            {
                var nodes = XmlConvert.DeserializeObject<multistatus>(rsp);
                return nodes;
            }
            catch (Exception ex)
            {
                //Console.WriteLine(ex.Message);
                return null;
            }
        }

        private async Task DownloadFile(string url,string savePath)
        {
            await Task.Delay(30);
            try
            {
                var request = GetHttpRequest(url);
                request.KeepAlive = true;
                //request.Headers.Add("Accept-Encoding", "gzip, deflate");
                request.Headers.Add("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
                request.Method = "GET";
                var rsp = request.GetResponse();
                byte[] buffer = new byte[1024];
                var length = 0;
                using(var file = File.Open(savePath, FileMode.Create))
                {
                    using (var stream = rsp.GetResponseStream())
                    {
                        while ((length = stream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            file.Write(buffer, 0, length);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public void Wait()
        {
            Task.WaitAll(tasks.ToArray());
        }

        public async Task Download(string rootDir,string url)
        {
            try
            {
                await Task.Delay(0);
                var nodes = await Request(url);
                if (nodes == null) return;
                foreach (var node in nodes.response)
                {
                    if (node.href.EndsWith("/"))
                    {
                        //链接带 / 说明是文件夹，继续 递归调用
                        var newUrl = $"{origin}{node.href}";
                        if (url.Trim('/') == newUrl.Trim('/')) continue;
                        await Download(rootDir, newUrl);
                    }
                    else
                    {
                        var savePath = $"{rootDir}/{node.href.Replace($"/svn/{rootPath}/", "")}";
                        savePath = System.Web.HttpUtility.UrlDecode(savePath);
                        var dir = Path.GetDirectoryName(savePath);
                        if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
                        var newUrl = $"{origin}{node.propstat.FirstOrDefault().prop.checkedin.href}";
                        Console.WriteLine(newUrl);
                        tasks.Add(DownloadFile(newUrl, savePath));
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

    }
}
